package soar.test.json.benchmark;

import java.text.SimpleDateFormat;
import java.time.Clock;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;

public class App
{
    public static void main(String args[])
    {
        new App().run();
    }

    private void run()
    {
        try
        {
            String split = "==================================================";
            System.out.println(split);

            generate();
            System.out.println(split);

            test_jackson();
            System.out.println(split);

            test_fastjson();
            System.out.println(split);

            test_gson();
            System.out.println(split);
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
    }

    private List<User> users;

    private void generate() throws Exception
    {
        String split = "------------------------------";

        System.out.println("generate");
        System.out.println(split);

        Clock clock = Clock.systemDefaultZone();

        Instant begin = clock.instant();

        final int REC_QT = 1000000;
        final String[] CHARS = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬",
                "癸" };
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Random random = new Random();
        int user_id = 1;
        int log_id = 1;

        List<User> users = new ArrayList<>();
        for (int i = 0; i < REC_QT; i++)
        {
            User user = new User();

            user.setId(user_id++);

            StringBuilder name = new StringBuilder();
            for (int j = 0; j < 3; j++)
            {
                name.append(CHARS[random.nextInt(CHARS.length)]);
            }
            user.setName(name.toString());

            Map<String, Integer> salary = new HashMap<>();
            salary.put("月薪", random.nextInt(5000) + 5000);
            salary.put("绩效", random.nextInt(5000) + 2000);
            user.setSalary(salary);

            List<Log> logs = new ArrayList<>();
            logs.add(new Log(log_id++,
                    format.parse(String.format("2010-%02d-01 %02d:%02d:%02d",
                            1 + random.nextInt(12), random.nextInt(24),
                            random.nextInt(60), random.nextInt(60))),
                    "入职"));
            logs.add(new Log(log_id++,
                    format.parse(String.format("2012-%02d-01 %02d:%02d:%02d",
                            1 + random.nextInt(12), random.nextInt(24),
                            random.nextInt(60), random.nextInt(60))),
                    "升职"));
            user.setLogs(logs);

            users.add(user);
        }

        this.users = users;

        Instant end = clock.instant();

        System.out.println(String.format("time cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));
    }

    private void test_jackson() throws Exception
    {
        String split = "------------------------------";

        System.out.println("jackson");
        System.out.println(split);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
                false);

        Clock clock = Clock.systemDefaultZone();

        Instant begin = clock.instant();
        List<String> encodes = new ArrayList<>();
        for (User user : users)
        {
            String encode = mapper.writeValueAsString(user);
            encodes.add(encode);
        }
        Instant end = clock.instant();
        System.out.println(String.format("encode cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));

        System.out.println();

        begin = clock.instant();
        List<User> decodes = new ArrayList<>();
        for (String encode : encodes)
        {
            User user = mapper.readValue(encode, User.class);
            decodes.add(user);
        }
        end = clock.instant();
        System.out.println(String.format("decode cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));
    }

    private void test_fastjson() throws Exception
    {
        String split = "------------------------------";

        System.out.println("fastjson");
        System.out.println(split);

        Clock clock = Clock.systemDefaultZone();

        Instant begin = clock.instant();
        List<String> encodes = new ArrayList<>();
        for (User user : users)
        {
            String encode = JSON.toJSONString(user,
                    SerializerFeature.WriteDateUseDateFormat);
            encodes.add(encode);
        }
        Instant end = clock.instant();
        System.out.println(String.format("encode cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));

        System.out.println();

        begin = clock.instant();
        List<User> decodes = new ArrayList<>();
        for (String encode : encodes)
        {
            User user = JSON.parseObject(encode, User.class);
            decodes.add(user);
        }
        end = clock.instant();
        System.out.println(String.format("decode cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));
    }

    private void test_gson() throws Exception
    {
        String split = "------------------------------";

        System.out.println("gson");
        System.out.println(split);

        Gson gson = new Gson();

        Clock clock = Clock.systemDefaultZone();

        Instant begin = clock.instant();
        List<String> encodes = new ArrayList<>();
        for (User user : users)
        {
            String encode = gson.toJson(user);
            encodes.add(encode);
        }
        Instant end = clock.instant();
        System.out.println(String.format("encode cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));

        System.out.println();

        begin = clock.instant();
        List<User> decodes = new ArrayList<>();
        for (String encode : encodes)
        {
            User user = gson.fromJson(encode, User.class);
            decodes.add(user);
        }
        end = clock.instant();
        System.out.println(String.format("decode cost: %d ms",
                end.toEpochMilli() - begin.toEpochMilli()));
    }
}

class User
{
    private int id;
    private String name;
    private Map<String, Integer> salary = new HashMap<>();
    private List<Log> logs = new ArrayList<>();

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public Map<String, Integer> getSalary()
    {
        return salary;
    }

    public void setSalary(Map<String, Integer> salary)
    {
        this.salary = salary;
    }

    public List<Log> getLogs()
    {
        return logs;
    }

    public void setLogs(List<Log> logs)
    {
        this.logs = logs;
    }

}

class Log
{
    private int id;
    private Date time;
    private String content;

    // 如定制构造方法，必须提供缺省构造方法
    public Log()
    {

    }

    public Log(int id, Date time, String content)
    {
        this.id = id;
        this.time = time;
        this.content = content;
    }

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public Date getTime()
    {
        return time;
    }

    public void setTime(Date time)
    {
        this.time = time;
    }

    public String getContent()
    {
        return content;
    }

    public void setContent(String content)
    {
        this.content = content;
    }

}
